package cn.com.nes.site.service.comecall.impl;


import cn.com.nes.mybatis.callcenter.mapper.CallRecordsMapper;
import cn.com.nes.mybatis.callcenter.mapper.CcCompanyMapper;
import cn.com.nes.mybatis.callcenter.mapper.MessageInfoMapper;
import cn.com.nes.mybatis.callcenter.mapper.UserMessageInfoMapper;
import cn.com.nes.mybatis.ctce.mapper.UserWxUsersMapper;
import cn.com.nes.site.entity.vo.system.ClientRegisterInfo;
import cn.com.nes.site.service.comecall.CallRecordsService;
import cn.com.nes.site.service.comecall.dto.CallOfTimeStatisticsDto;
import cn.com.nes.site.service.comecall.dto.CallRecordsDto;
import cn.com.nes.site.service.comecall.dto.CallWorkOrderStatisticsDto;
import cn.com.nes.site.service.comecall.entity.CallRecords;
import cn.com.nes.site.service.comecall.entity.MessageInfo;
import cn.com.nes.site.service.comecall.entity.UserMessageInfo;
import cn.com.nes.site.service.comecall.vo.CallOfTimeStatisticsVo;
import cn.com.nes.site.service.comecall.vo.CallQuantityStatisticsVo;
import cn.com.nes.site.service.comecall.vo.CallRecordsVO;
import cn.com.nes.site.service.comecall.vo.CallWorkOrderStatisticsVo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CallRecordsServiceImpl extends ServiceImpl<CallRecordsMapper, CallRecords>  implements CallRecordsService {

    @Resource
    private CallRecordsMapper callRecordsMapper;

    @Resource
    private MessageInfoMapper messageInfoMapper;

    @Resource
    private UserMessageInfoMapper userMessageInfoMapper;

    @Resource
    private UserWxUsersMapper userWxUsersMapper;

    @Resource
    private CcCompanyMapper ccCompanyMapper;

    private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(15);
    private Map<String, ScheduledFuture<?>> scheduledFutureMap = new ConcurrentHashMap<>();
    private ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();

    @Override
    public Page<CallRecordsDto> getCallRecords(CallRecordsVO vo) {
        if (vo == null || vo.getCompanyId() == null || vo.getCompanyAttachId() == null) {
            return null;
        }
        if(vo.getPage() == null) {
            vo.setPage(1);
        }
        if(vo.getSize() == null) {
            vo.setSize(10);
        }
        Page<CallRecordsDto> page=new Page<>(vo.getPageid(),vo.getPagesize());
        List<CallRecordsDto> res = callRecordsMapper.getCallRecords(page,vo);
        for (CallRecordsDto re : res) {
            String s = secToTime(re.getDuration() == null ? 0 : Integer.valueOf(re.getDuration()));
            re.setDuration(s);
        }
        return page.setRecords(res);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer saveCallRecords(String appId, String secret, List<CallRecords> vo) {
        if (CollectionUtils.isEmpty(vo)) {
            return 0;
        }
        if (StringUtils.isEmpty(appId) || StringUtils.isEmpty(secret)) {
            throw new RuntimeException("appId和secret不能为空");
        }
        ClientRegisterInfo clientRegisterInfo = ccCompanyMapper.getClientRegisterInfoByAppId(appId);
        if (clientRegisterInfo == null) {
            throw new RuntimeException("appId无效");
        }
        if (!secret.equals(clientRegisterInfo.getAppSecret())) {
            throw new RuntimeException("secret无效");
        }

        vo.forEach(v -> {
            v.setCompanyId(clientRegisterInfo.getCompanyId());
            v.setCompanyAttachId(clientRegisterInfo.getCompanyAttachId());
        });

        Set<String> existCallRecords = callRecordsMapper.selectByCompanyIdAndCdrId(vo)
                .stream()
                .map(t -> t.getCompanyId() + "/" + t.getCdrId())
                .collect(Collectors.toSet());

        List<CallRecords> records = vo.stream().filter(t -> {
            String key = t.getCompanyId() + "/" + t.getCdrId();
            return !existCallRecords.contains(key);
        }).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(records)) {
            return 0;
        }
        this.saveBatch(records);
        sendAMessage(records);
        return records.size();
    }

    private void sendAMessage(List<CallRecords> records) {
        //获取半小时以内的通话
        records = records.stream().filter(item -> System.currentTimeMillis() - item.getCalldate().getTime() <= 1000 * 60 * 60 * 6 && "呼入".equals(item.getInout())).collect(Collectors.toList());
        //查询user_wx_users存在的phone
        if (records != null && records.size() == 0) return;
        List<Map> phoneAndIdList = userWxUsersMapper.selectUserWxUsersByPhone(records);
        for (CallRecords record : records) {
            MessageInfo messageInfo = new MessageInfo();
            messageInfo.setCompanyId(record.getCompanyId());
            messageInfo.setIsPush((byte) 0);
            messageInfo.setType((byte) 0);
            messageInfo.setTitle("系统提醒");
            messageInfo.setDesc("感谢您来电，我们会尽快为您处理！");
            messageInfo.setGmtCreate(System.currentTimeMillis());
            //往message_info插入数据
            messageInfoMapper.insertByMessageInfo(messageInfo);
            for (Map map : phoneAndIdList) {
                if (record.getSrc().equals(String.valueOf(map.get("phone")))) {
                    UserMessageInfo userMessageInfo = new UserMessageInfo();
                    userMessageInfo.setUserId((Long) map.get("id"));
                    userMessageInfo.setMessageId(messageInfo.getId());
                    userMessageInfo.setIsRead(((byte) 0));
                    userMessageInfo.setGmtCreate(System.currentTimeMillis());
                    //往user_message_info插入数据
                    userMessageInfoMapper.insertByUserMessageInfo(userMessageInfo);
                }
            }
        }
    }

    private String secToTime(int time) {
        String timeStr = null;
        int hour = 0;
        int minute = 0;
        int second = 0;
        if (time <= 0)
            return "00:00";
        else {
            minute = time / 60;
            if (minute < 60) {
                second = time % 60;
                timeStr = unitFormat(minute) + ":" + unitFormat(second);
            } else {
                hour = minute / 60;
                if (hour > 99)
                    return "99:59:59";
                minute = minute % 60;
                second = time - hour * 3600 - minute * 60;
                timeStr = unitFormat(hour) + ":" + unitFormat(minute) + ":" + unitFormat(second);
            }
        }
        return timeStr;
    }

    private String unitFormat(int i) {
        String retStr = null;
        if (i >= 0 && i < 10)
            retStr = "0" + Integer.toString(i);
        else
            retStr = "" + i;
        return retStr;
    }

    @Override
    public Map<String, Object> getCallQuantityStatistics(CallQuantityStatisticsVo vo) {
        List<Map<String, Object>> list = callRecordsMapper.getCallQuantityStatistics(vo);
        Map<String, Object> result = new HashMap<>();
        result.put("incount", "0");
        result.put("inproportion", "0%");
        result.put("intitle", "呼入");
        result.put("outcount", "0");
        result.put("outproportion", "0%");
        result.put("outtitle", "呼出");
        result.put("count", "0");

        for(Map<String, Object> map : list) {
            if("呼入".equals(map.get("inout"))) {
                result.put("incount", map.get("cnt").toString());
            } else if("呼出".equals(map.get("inout"))) {
                result.put("outcount", map.get("cnt").toString());
            }
        }

        Integer incount = Integer.valueOf((String) result.get("incount"));
        Integer outcount = Integer.valueOf((String) result.get("outcount"));
        result.put("incount", incount.toString());
        result.put("outcount", outcount.toString());
        result.put("count", String.valueOf(incount + outcount));

        if(incount + outcount > 0) {
            result.put("inproportion", new BigDecimal(incount.toString()).divide(new BigDecimal(incount + outcount), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue() + "%");
            result.put("outproportion", new BigDecimal(outcount.toString()).divide(new BigDecimal(incount + outcount), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue() + "%");
        }

        return result;
    }

    @Override
    public List<CallOfTimeStatisticsDto> getCallOfTimeStatistics(CallOfTimeStatisticsVo vo) {
        List<CallOfTimeStatisticsDto> list = null;
            list = callRecordsMapper.getCallOfTimeStatistics(vo);
            list.forEach(t-> {
                if(t.getIn() == null) {
                    t.setIn(0);
                }
                if(t.getOut() == null) {
                    t.setOut(0);
                }
                if(t.getCount() == null) {
                    t.setCount(t.getIn() + t.getOut());
                }
                if(t.getCount() > 0) {
                    t.setInproportion(new BigDecimal(t.getIn().toString()).divide(new BigDecimal(t.getCount()), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue() + "%");
                    t.setOutproportion(new BigDecimal(t.getOut().toString()).divide(new BigDecimal(t.getCount()), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue() + "%");
                } else {
                    t.setInproportion("0%");
                    t.setOutproportion("0%");
                }
            });
        return list;
    }

    @Override
    public List<CallWorkOrderStatisticsDto> getCallWorkOrderStatistics(CallWorkOrderStatisticsVo vo) {
        List<CallWorkOrderStatisticsDto> list = callRecordsMapper.getCallWorkOrderStatistics(vo);

        int sum = list.stream().peek(t-> {
            if(t.getCnt() == null) {
                t.setCnt(0);
            }
        }).mapToInt(CallWorkOrderStatisticsDto::getCnt).sum();

        list.forEach(t-> {
            if(sum > 0) {
                double val = new BigDecimal(t.getCnt()).divide(new BigDecimal(sum), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).doubleValue();
                t.setProportion(val);
            } else {
                t.setProportion(0.);
            }
        });

        return list;
    }
}
